﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Text;
using System.Net;
using System.IO;
using System.Xml;
using Mono.Data.Sqlite;
using MOM.DB.Access;

#region COPYRIGHT
/*
	COPYRIGHT © 2007 - 2008 Ulrik S. Andersson.
	
	This file is part of MOM.

    MOM is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or (at your option) any later version.

    MOM is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more details.

    You should have received a copy of the GNU General Public License along with MOM.  If not, see <http://www.gnu.org/licenses/>.
*/
#endregion

namespace MOM.DB.JSON
{
	/// <summary>
	/// Description of LastFm
	/// </summary>
	public class LastFm : BasePage
	{	
		
		protected void Page_Load(object sender, EventArgs e)
		{
			string action = Request.QueryString["ac"];
			string artist = Request.QueryString["a"];
			if (artist.IndexOf(", The") > 0)
				artist = "The " + artist.Replace(", The", "");
			artist = artist.Replace("&", " And ");

			XmlDocument xml = null;
			int i = 0;
			StringBuilder sbJson = new StringBuilder("{Result:[");
			switch (action)
			{
				case "similar":
					xml = RequestXml("http://ws.audioscrobbler.com/1.0/artist/" + Server.UrlEncode(artist) + "/similar.xml");
					XmlNodeList nlArtist = xml.SelectNodes("/similarartists/artist");
					
					foreach (XmlNode ndArtist in nlArtist)
					{
						string strArtist = ndArtist.SelectSingleNode("name").InnerText.Replace("'", "\\'");
						string url = ndArtist.SelectSingleNode("url").InnerText;
						string img = ndArtist.SelectSingleNode("image").InnerText;
						
						sbJson.Append("{Artist:'" + strArtist + "',Image:'" + img + "',Url:'" + url + "'},");

						if (i > 19)
							break;
						i++;
					}
					if (nlArtist.Count > 0)
						sbJson.Remove(sbJson.Length - 1, 1);
					sbJson.Append("]}");
					break;
				case "topalbums":
					xml = RequestXml("http://ws.audioscrobbler.com/1.0/artist/" + Server.UrlEncode(artist) + "/topalbums.xml");
					XmlNodeList nlAlbum = xml.SelectNodes("/topalbums/album");

					foreach (XmlNode ndAlbum in nlAlbum)
					{
						string strAlbum = ndAlbum.SelectSingleNode("name").InnerText.Replace("'", "\\'");
						string img = "";
						XmlNode ndImg = ndAlbum.SelectSingleNode("image");
						if (ndImg != null)
						{
							ndImg = ndImg.SelectSingleNode("small");
							if (ndImg != null)
								img = ndImg.InnerText;
						}

						sbJson.Append("{Album:'" + strAlbum + "',Image:'" + img + "'},");

						if (i > 9)
							break;
						i++;
					}
					if (nlAlbum.Count > 0)
						sbJson.Remove(sbJson.Length - 1, 1);
					sbJson.Append("]}");
					break;
				case "toptracks":
					xml = RequestXml("http://ws.audioscrobbler.com/1.0/artist/" + Server.UrlEncode(artist) + "/toptracks.xml");
					XmlNodeList nlTrack = xml.SelectNodes("/mostknowntracks/track");

					foreach (XmlNode ndTrack in nlTrack)
					{
						string name = ndTrack.SelectSingleNode("name").InnerText.Replace("'", "\\'");
						sbJson.Append("'" + name + "',");
					}
					if (nlTrack.Count > 0)
						sbJson.Remove(sbJson.Length - 1, 1);

					sbJson.Append("]}");

					break;
				case "recommend":
					Dictionary<string, int> localArtists = new Dictionary<string, int>();
					
					//Get top 10 artists based on the last 300 played tracks
					string sql = @"SELECT tblArtist.ArtistName AS ArtistName, Count(*) AS ArtistCount
								FROM tblTrack 
								INNER JOIN tblArtist ON tblTrack.ArtistId = tblArtist.ArtistId 
								WHERE tblTrack.TrackId 
								IN (SELECT TrackId FROM tblHistory WHERE UserId = {0} ORDER BY DatePlayed DESC LIMIT 0, 300)
								GROUP BY tblArtist.ArtistName
								ORDER BY ArtistCount DESC";
					using (SqliteServer conn = new SqliteServer("Default", true))
					{
						i = 0;
						using (SqliteDataReader reader = conn.GetDataReader(sql, UserId))
						{
							while (reader.Read() && i < 10)
							{
								if (reader["ArtistName"].ToString().ToLower().IndexOf("various artist") > -1)
									continue;
								localArtists.Add(reader["ArtistName"].ToString(), Convert.ToInt32(reader["ArtistCount"]));
								i++;
							}
						}
					}

					//Get related artists for local artists
					Dictionary<string, double> lastfmArtists = new Dictionary<string, double>();
					foreach (KeyValuePair<string, int> a in localArtists)
					{
						xml = RequestXml("http://ws.audioscrobbler.com/1.0/artist/" + Server.UrlEncode(a.Key) + "/similar.xml");
						nlArtist = xml.SelectNodes("/similarartists/artist");
						i = 0;
						foreach (XmlNode ndArtist in nlArtist)
						{
							string name = ndArtist.SelectSingleNode("name").InnerText;
							if (name.ToLower().StartsWith("the "))
								name = name.Substring(4) + ", The";
							double match = double.Parse(ndArtist.SelectSingleNode("match").InnerText.Replace(".", ","));
							if (!lastfmArtists.ContainsKey(name))
								lastfmArtists.Add(name, match * (double)a.Value);
							else
								lastfmArtists[name] += match * (double)a.Value;
							if (i >= 9)
								break;
							i++;
						}
					}

					//Sort LastFM Result
					List<KeyValuePair<string, double>> sortedArtists = new List<KeyValuePair<string, double>>();
					sortedArtists.AddRange(lastfmArtists);
					sortedArtists.Sort(
						delegate(KeyValuePair<string, double> kvp1, KeyValuePair<string, double> kvp2)
						{
							return Comparer<double>.Default.Compare(kvp2.Value, kvp1.Value);
						}
					);

					//Get existing artists in related artists
					localArtists.Clear();
					StringBuilder sbArtist = new StringBuilder();
					foreach (KeyValuePair<string, double> kvp in sortedArtists)
					{
						sbArtist.Append("'" + kvp.Key.Replace("'", "''") + "',");
					}

					sql = "SELECT ArtistName FROM tblArtist WHERE ArtistName IN (" + sbArtist.ToString().TrimEnd(',') + ")";
					using (SqliteServer conn = new SqliteServer("Default", true))
					{
						using (SqliteDataReader reader = conn.GetDataReader(sql))
						{
							while (reader.Read())
							{
								localArtists.Add(reader["ArtistName"].ToString(), 1);
							}
						}
					}


					foreach (KeyValuePair<string, double> kvp in sortedArtists)
					{
						bool exists = false;
						foreach (KeyValuePair<string, int> a in localArtists)
						{
							if (kvp.Key.ToLower() == a.Key.ToLower())
							{
								exists = true;
								break;
							}
						}

						sbJson.Append("{Artist:'" + kvp.Key.Replace("'", "\\'") + "',Exists:" + exists.ToString().ToLower() + "},");
					}
					sbJson.Remove(sbJson.Length - 1, 1);
					sbJson.Append("]}");
					break;
			}
			
			Response.ContentType = "text/plain";
			Response.Write(sbJson.ToString());
		}
		
		private XmlDocument RequestXml(string url)
        {
            WebClient wc = new WebClient();
            XmlDocument xmlDoc = new XmlDocument();
            MemoryStream memStream = null;

            try
            {
                wc.Headers.Add("Content-Type", "application/x-www-form-urlencoded");
                byte[] byteResponse = wc.DownloadData(url);
                memStream = new MemoryStream(byteResponse);
                xmlDoc = new XmlDocument();
                xmlDoc.Load(memStream);
            }
            finally
            {
                if (memStream != null)
                {
                    memStream.Flush();
                    memStream.Close();
                }
                wc.Dispose();
            }

            return xmlDoc;
        }				
	}
}
